#pragma once

#include <string>
#include <string.h>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <memory>

namespace Http_ns
{
    const static std::string base_sep = "\r\n";
    const static std::string line_sep = ": ";
    const static std::string arg_sep = "?";
    const static std::string homepage = "login.html"; //"index.html"; //"login.html";
    const static std::string suffixsep = ".";
    const static std::string prefixpath = "wwwroot"; // web根目录
    const static std::string httpversion = "HTTP/1.0";
    const static std::string spacesep = " ";

    // 服务端交给客户端的请求
    class Request
    {
    private:
        std::string Getline(std::string &reqstr)
        {
            auto pos = reqstr.find(base_sep);
            if (pos == std::string::npos)
                return std::string();
            std::string line = reqstr.substr(0, pos);
            reqstr.erase(0, line.size() + base_sep.size());

            // 当读完报头读到空行时返回的也是空串，因此需要特殊处理
            return line.empty() ? base_sep : line;
        }

        // 处理一下得到的请求行
        void ParseReqLine()
        {
            // stringstream 可以将字符串转化为字符流
            std::stringstream ss(_req_line);   // cin >>
            ss >> _method >> _url >> _version; // /a/b/c.html or /login?user=XXX&passwd=1234 /register

            // 方法和版本得到了，然后还要处理url

            // 如果是GET方法，需要提取出url中携带的参数
            if (strcasecmp(_method.c_str(), "GET") == 0)
            {
                auto pos = _url.find(arg_sep);
                if (pos != std::string::npos)
                {
                    // 将参数提取到正文中
                    _body_text += _url.substr(pos + arg_sep.size());
                    // 将参数分割出去，只留下path路径
                    _url.resize(pos);
                }
            }

            // 添加路径
            _path += _url;
            // 如果没有添加路径，只有一个 '/' ， 那就默认跳转到主页路径
            if (_path[_path.size() - 1] == '/')
            {
                _path += homepage;
            }

            // 获取路径中 你要访问的资源的后缀，知道它的类型
            auto pos = _path.rfind(suffixsep);
            if (pos != std::string::npos)
            {
                _suffix += _path.substr(pos);
            }
            else
            {
                _suffix += ".default";
            }
        }

        // 将请求报头中的 属性字段 提取出来放入哈希表中
        void ParseHeaders()
        {
            for (auto &e : _req_headers)
            {
                auto pos = e.find(line_sep);
                // 不完整
                if (pos == std::string::npos)
                    continue;
                std::string k = e.substr(0, pos);
                std::string v = e.substr(pos + line_sep.size());
                // 内容为空
                if (k.empty() || v.empty())
                    continue;
                _headers_kv.insert(std::make_pair(k, v));
            }
        }


    public:
        Request() : _blank_line(base_sep), _path(prefixpath)
        {
        }
        ~Request() {}

        // 反序列化
        void DeSerialize(std::string &reqstr)
        {
            // 先读取请求行
            _req_line = Getline(reqstr);
            // 再读取请求报头
            std::string header;
            while (true)
            {
                // 读取一行报头
                header = Getline(reqstr);
                // 如果请求行没有换行符，则请求不完整，退出循环
                // 如果读取到了最后一行请求行，退出循环
                if (header.empty() || header == base_sep)
                    break;

                // 得到一行请求行，方便后续处理其内容(属性)
                _req_headers.push_back(header);
            }

            // 处理完后如果有正文
            if (!reqstr.empty())
            {
                _body_text = reqstr;
            }

            // 处理请求行
            ParseReqLine();
            // 处理请求报头
            ParseHeaders();
        }

        std::string Content()
        {
            return _body_text;
        }

        std::string Path()
        {
            return _path;
        }

        std::string Suffix()
        {
            return _suffix;
        }

        std::string Method()
        {
            return _method;
        }

        std::string Url()
        {
            return _url;
        }

    private:
        std::string _req_line;                 // 请求行
        std::vector<std::string> _req_headers; // 相应报头
        std::string _blank_line;               // 空行
        std::string _body_text;                // 正文

        // 具体的属性
        std::string _method;                                      // 请求方法
        std::string _url;                                         // URL
        std::string _path;                                        // URL中的路径
        std::string _suffix;                                      // URL中携带的资源后缀
        std::string _version;                                     // 协议版本
        std::unordered_map<std::string, std::string> _headers_kv; // 报头中的字段和内容 对
    };

    // 服务端交给客户端的应答
    class Response
    {
    public:
        Response():_version(httpversion), _blank_line(base_sep)
        {}
        ~Response()
        {}

        void AddCode(int code, const std::string& desc)
        {
            _code = code;
            _desc = desc;
        }

        void AddBodyText(const std::string& body_text)
        {
            _resp_body_text = body_text;
        }

        void AddHeader(const std::string& k, const std::string& v)
        {
            _headers_kv[k] = v;
        }

        // 应答序列化
        std::string Serialize()
        {
            // 1. 构建状态行
            _status_line = _version + spacesep + std::to_string(_code) + spacesep + _desc + base_sep;

            // 2. 构建应答报头
            for(auto& e : _headers_kv)
            {
                std::string header_line = e.first + line_sep + e.second + base_sep;
                _resp_headers.push_back(header_line);
            }

            // 3. 空行和正文
            // 空行本身就有，正文也不需要处理

            // 4. 序列化
            std::string respstr = _status_line;
            for(auto& line : _resp_headers)
            {
                respstr += line;
            }
            respstr += _blank_line;
            respstr += _resp_body_text;

            return respstr;
        }

    private:
        // http基本格式
        std::string _status_line;              // 请求行
        std::vector<std::string> _resp_headers; // 相应报头
        std::string _blank_line;               // 空行
        std::string _resp_body_text;           // 正文

        // 响应的属性
        std::string _version;                  // 协议版本
        int _code;                             // 状态码
        std::string _desc;                     // 状态码描述
        std::unordered_map<std::string,std::string> _headers_kv; // 报头中的字段和内容 对
    };

    // 工厂模式
    class Factory
    {
    public:
        static std::shared_ptr<Request> BuildRequestDefault()
        {
            return std::make_shared<Request>();
        }
        static std::shared_ptr<Response> BuildResponseDefault()
        {
            return std::make_shared<Response>();
        }
    };
}